"""
日志记录中间件
自动记录HTTP请求和响应
"""

import time
import uuid
import json
from flask import request, g, current_app
from flask_login import current_user
from services.shared.log_utils import log_user_action


class LoggingMiddleware:
    """HTTP请求日志记录中间件"""
    
    def __init__(self, app=None):
        self.app = app
        if app is not None:
            self.init_app(app)
    
    def init_app(self, app):
        """初始化中间件"""
        app.before_request(self.before_request)
        app.after_request(self.after_request)
        app.teardown_appcontext(self.teardown_request)
    
    def before_request(self):
        """请求开始前的处理"""
        # 生成请求ID
        g.request_id = str(uuid.uuid4())
        g.start_time = time.time()
        
        # 记录请求开始
        if self.should_log_request():
            self.log_request_start()
    
    def after_request(self, response):
        """请求结束后的处理"""
        if self.should_log_request():
            self.log_request_end(response)
        return response
    
    def teardown_request(self, exception=None):
        """请求清理时的处理"""
        if exception and self.should_log_request():
            self.log_request_exception(exception)
    
    def should_log_request(self):
        """判断是否应该记录此请求"""
        # 跳过静态文件请求
        if request.endpoint == 'static':
            return False
        
        # 跳过健康检查请求
        if request.path in ['/health', '/ping', '/status']:
            return False
        
        # 跳过某些API端点（可配置）
        skip_paths = getattr(current_app.config, 'LOG_SKIP_PATHS', [])
        if request.path in skip_paths:
            return False
        
        return True
    
    def log_request_start(self):
        """记录请求开始"""
        try:
            # 获取用户ID
            user_id = None
            if hasattr(current_user, 'id'):
                user_id = current_user.id
            
            # 获取请求大小
            request_size = len(request.get_data()) if request.get_data() else 0
            
            # 准备详细信息
            details = {
                'endpoint': request.endpoint,
                'method': request.method,
                'url': request.url,
                'remote_addr': request.remote_addr,
                'user_agent': request.headers.get('User-Agent', ''),
                'content_type': request.content_type,
                'content_length': request.content_length,
                'request_size': request_size,
                'args': dict(request.args),
                'form_keys': list(request.form.keys()) if request.form else [],
                'headers': dict(request.headers)
            }
            
            # 过滤敏感信息
            self.filter_sensitive_data(details)
            
            log_user_action(
                level='DEBUG',
                module='http_middleware',
                message=f'请求开始: {request.method} {request.path}',
                details=json.dumps(details, ensure_ascii=False),
                user_id=user_id,
                action='request_start',
                resource_type='http',
                resource_id=request.endpoint,
                request_id=g.request_id,
                request_method=request.method,
                request_url=request.url,
                tags=['http', 'request_start']
            )
            
        except Exception as e:
            # 日志记录失败不应该影响正常请求
            current_app.logger.error(f"记录请求开始日志失败: {e}")
    
    def log_request_end(self, response):
        """记录请求结束"""
        try:
            # 计算执行时间
            execution_time = (time.time() - g.start_time) * 1000
            
            # 获取用户ID
            user_id = None
            if hasattr(current_user, 'id'):
                user_id = current_user.id
            
            # 获取响应大小
            response_size = 0
            if hasattr(response, 'content_length') and response.content_length:
                response_size = response.content_length
            elif hasattr(response, 'data'):
                response_size = len(response.data)
            
            # 确定日志级别
            level = 'INFO'
            severity = 0
            
            if response.status_code >= 500:
                level = 'ERROR'
                severity = 5
            elif response.status_code >= 400:
                level = 'WARNING'
                severity = 2
            elif execution_time > 5000:  # 超过5秒
                level = 'WARNING'
                severity = 3
            elif execution_time > 1000:  # 超过1秒
                severity = 1
            
            # 准备详细信息
            details = {
                'status_code': response.status_code,
                'response_size': response_size,
                'execution_time': execution_time,
                'content_type': response.content_type,
                'headers': dict(response.headers)
            }
            
            log_user_action(
                level=level,
                module='http_middleware',
                message=f'请求完成: {request.method} {request.path} - {response.status_code}',
                details=json.dumps(details, ensure_ascii=False),
                user_id=user_id,
                action='request_complete',
                resource_type='http',
                resource_id=request.endpoint,
                execution_time=execution_time,
                status_code=response.status_code,
                request_id=g.request_id,
                request_method=request.method,
                request_url=request.url,
                response_size=response_size,
                severity=severity,
                tags=['http', 'request_complete']
            )
            
        except Exception as e:
            # 日志记录失败不应该影响正常请求
            current_app.logger.error(f"记录请求结束日志失败: {e}")
    
    def log_request_exception(self, exception):
        """记录请求异常"""
        try:
            # 计算执行时间
            execution_time = (time.time() - g.start_time) * 1000
            
            # 获取用户ID
            user_id = None
            if hasattr(current_user, 'id'):
                user_id = current_user.id
            
            # 准备详细信息
            details = {
                'exception_type': type(exception).__name__,
                'exception_message': str(exception),
                'execution_time': execution_time
            }
            
            log_user_action(
                level='ERROR',
                module='http_middleware',
                message=f'请求异常: {request.method} {request.path} - {str(exception)}',
                details=json.dumps(details, ensure_ascii=False),
                user_id=user_id,
                action='request_exception',
                resource_type='http',
                resource_id=request.endpoint,
                execution_time=execution_time,
                status_code=500,
                request_id=g.request_id,
                request_method=request.method,
                request_url=request.url,
                severity=5,
                error_code=type(exception).__name__,
                tags=['http', 'request_exception', 'error']
            )
            
        except Exception as e:
            # 日志记录失败不应该影响正常请求
            current_app.logger.error(f"记录请求异常日志失败: {e}")
    
    def filter_sensitive_data(self, details):
        """过滤敏感数据"""
        sensitive_keys = [
            'password', 'passwd', 'pwd', 'secret', 'token', 'key',
            'authorization', 'cookie', 'session', 'csrf'
        ]
        
        # 过滤headers中的敏感信息
        if 'headers' in details:
            for key in list(details['headers'].keys()):
                if any(sensitive in key.lower() for sensitive in sensitive_keys):
                    details['headers'][key] = '***FILTERED***'
        
        # 过滤args中的敏感信息
        if 'args' in details:
            for key in list(details['args'].keys()):
                if any(sensitive in key.lower() for sensitive in sensitive_keys):
                    details['args'][key] = '***FILTERED***'
        
        # 过滤form_keys中的敏感信息
        if 'form_keys' in details:
            details['form_keys'] = [
                key if not any(sensitive in key.lower() for sensitive in sensitive_keys)
                else '***FILTERED***'
                for key in details['form_keys']
            ]